<template>
  <el-scrollbar ref="scrollRef" :max-height="290" @scroll="scroll">
    <ul ref="dynamicDatasRef" class="dynamicDatas">
      <li
        class="clearfix"
        v-for="(
          [key, { userId, remark, avatar, time, content, imgs, thumbs, comments }], index
        ) in data"
        :key="key"
      >
        <img
          class="sender-left"
          :src="avatar"
          alt=""
          @click="openInfo(userId, avatar, $event)"
        />
        <div class="sender-right">
          <div class="sender-remark clearfix">
            <span>{{ remark }}</span
            ><SvgIcon
              v-if="isFriend"
              icon-class="more"
              popper-class="dynamic-opea"
              @click="openMenu(key, userId, $event)"
            />
          </div>
          <p
            class="sender-text"
            v-if="content"
            v-filterText="{ content, imgClass: 'dynamic-text__emotion' }"
          ></p>
          <div
            v-if="imgs.length"
            :class="{
              'sender-imgs': true,
              'sender-imgs__one': imgs.length === 1,
              'sender-imgs__two': imgs.length === 2,
              'sender-imgs__three': imgs.length > 2,
            }"
          >
            <img
              v-for="(item, index) in imgs"
              :key="index"
              :src="item"
              alt=""
              @click="imgClick(imgs, index)"
            />
          </div>
          <p class="sender-time" v-time="time"></p>
          <template v-if="thumbs?.size || comments?.size">
            <thumb-comment
              :thumbs="thumbs"
              :comments="comments"
              :self-id="selfId"
              :dynamicer-id="userId"
              :dynamic-id="key"
              :is-friend="isFriend"
              @open-info="openInfoInvoke"
              @open-menu="openCommentMenu"
            ></thumb-comment
          ></template>
        </div>
        <el-divider
          :class="{
            'sender-divider': true,
            'sender-divider__last': index === data.size - 1,
          }"
        />
      </li>
      <li v-if="scrollBottom" class="loading-more">
        <SvgIcon icon-class="loadingCircle" class="spinMess" v-if="!isLoadingMoreError" />
        <span class="loading-more__error" v-else
          >请求失败，点击 <span @click="requestDatas(lastId)">重试</span></span
        >
      </li>
    </ul></el-scrollbar
  >
  <img-browse
    v-model="showImgBrowse"
    v-model:img-index="imgIndex"
    :imgs="imgs"
  ></img-browse>
  <template v-if="isMounted">
    <usr-info-card
      ref="userInfoRef"
      v-model="showInfo"
      :user-id="userInfoId"
      to="#dynamicDatas"
      setup-to="#dynamic"
      width="60%"
      @update-position="updatePosition"
      :is-friend-dynamic="isFriend"
      @success="modifyInfoSuccess"
    ></usr-info-card
  ></template>
  <template v-if="isFriend">
    <dynamic-menu
      ref="menuRef"
      v-model="showMenu"
      :is-thumb="isThumb"
      :dynamic-id="dynamicId"
      :is-delete="selfId === currentId"
      :is-noself="selfId !== otherId"
      @thumb="thumb"
      @comment="comment"
    ></dynamic-menu>
    <comment-menu
      ref="commentMenuRef"
      @delete-comment="deleteComment"
      @comment="comment"
    ></comment-menu
  ></template>
</template>

<script lang="ts" setup>
import { ref, reactive, nextTick, onMounted, watch, inject } from "vue";
import { useDynamicPinia } from "@/pinia/dynamic";
import vTime from "@/directives/dynamicTime";
import imgBrowse from "@/components/ui-components/imgBrowse.vue";
import usrInfoCard from "@/components/messages/colRight/detailMessage/usrInfoCard.vue";
import vFilterText from "@/directives/filterText";
import dynamicMenu from "./menu.vue";
import thumbComment from "./thuComment.vue";
import commentMenu from "./commentMenu.vue";

const props = defineProps<{
  data: Map<string, Dynamic>;
  isLast: boolean;
  selfId: string;
  otherId: string;
  isSelf: boolean;
  isFriend: boolean;
}>();

const emits = defineEmits<{
  (e: "update:isLast", isLast: boolean): void;
}>();

const dynamicStore = useDynamicPinia();

/**
 * 是否显示动态操作菜单
 */
const showMenu = ref<boolean>(false);
/**
 * 给操作菜单一个ref属性
 */
const menuRef = ref<any>();
/**
 * 当前用户操作的动态id值
 */
const dynamicId = ref<string>("");
/**
 * 当前查看用户资料的账号值
 */
const currentId = ref<string>("");
/**
 * 自己是否点赞过该动态
 */
const isThumb = ref<boolean>(false);
const isLoadingThumb = inject("isLoadingThumb") as any;

// 打开操作菜单
const openMenu = (key: string, userId: string, e: MouseEvent) => {
  if (!isLoadingThumb.value) {
    const data = props.data.get(key)!;
    data?.thumbs?.has(props.selfId) ? (isThumb.value = true) : (isThumb.value = false);
    dynamicId.value = key;
    currentId.value = userId;
    if (!showMenu.value) showMenu.value = true;
    nextTick(() => {
      const y: number = e.clientY;
      const x: number = e.clientX;
      const rect = document.getElementById("dynamicDatas")?.getBoundingClientRect()!;
      const hei: number = (menuRef.value?.$refs.menuRef as any).offsetHeight;
      const wid: number = (menuRef.value?.$refs.menuRef as any).offsetWidth;
      const toBottom: number = rect.y + rect.height - y;
      (menuRef.value?.$refs.menuRef as any).style.cssText += `top: ${
        toBottom >= hei ? y - rect.y : y - rect.y - hei
      }px; left: ${x - rect.x - wid}px`;
    });
  }
};

// 当该用户是在好友动态里面进行点赞
const thumb = (payload: { remark: string; userId: string; dynamicId: string }) => {
  if (props.otherId !== props.selfId) {
    const data = props.data.get(payload.dynamicId);
    if (data) {
      if (data.thumbs.has(payload.userId)) {
        data.thumbs.delete(payload.userId);
        isThumb.value = false;
      } else {
        data.thumbs.set(payload.userId, {
          remark: payload.remark,
        });
        isThumb.value = true;
      }
    }
  }
};

// 当该用户是在好友动态里面评论时添加评论
const comment = (payload: {
  info: DynamicCommenter & { commentContent: string };
  commentId: string;
  dynamicId: string;
}) => {
  if (props.otherId !== props.selfId) {
    const data = props.data.get(payload.dynamicId);
    if (data) data.comments.set(payload.commentId, payload.info);
  }
};

// 当该用户是在好友动态里面评论里面删除评论时
const deleteComment = (commentId: string, dynamicId: string) => {
  if (props.otherId !== props.selfId) {
    const data = props.data.get(dynamicId);
    if (data) data.comments.delete(commentId);
  }
};

/**
 * 给滚动条一个ref属性
 */
const scrollRef = ref<any>();
watch(
  () => props.data.size,
  (newSize) => {
    if (newSize)
      nextTick(() => {
        scrollRef.value.update();
        getScrollMax();
      });
  }
);

/**
 * 用户浏览的图片集合
 */
const imgs = reactive<string[]>([]);
/**
 * 是否显示图片浏览组件
 */
const showImgBrowse = ref<boolean>(false);
/**
 * 当前用户所浏览的图片的索引值
 */
const imgIndex = ref<number>(0);
// 点击图片进行浏览
const imgClick = (item: string[], index: number) => {
  if (!showInfo.value) {
    imgs.length && imgs.splice(0);
    imgs.push(...item);
    showImgBrowse.value = true;
    imgIndex.value = index;
  }
};

/**
 * 是否需要打开用户信息卡片
 */
const showInfo = ref<boolean>(false);
/**
 * 给资料卡片组件一个ref属性，便于通过$refs访问
 */
const userInfoRef = ref<typeof usrInfoCard>();
/**
 * 当前用户点击的位置坐标
 */
const eventCoord = ref<{
  x: number;
  y: number;
}>({
  x: 0,
  y: 0,
});
/**
 * 定位元素距浏览器顶部和左边距的距离
 */
const rectPosition = ref<{
  x: number;
  y: number;
  wid: number;
  hei: number;
}>({
  x: 0,
  y: 0,
  wid: 0,
  hei: 0,
});

// 更新资料卡片的位置
const updatePosition = () => {
  const hei: number = (userInfoRef.value?.$refs.userInfoRef as any).offsetHeight;
  const wid: number = (userInfoRef.value?.$refs.userInfoRef as any).offsetWidth;
  const top: number = rectPosition.value.y + rectPosition.value.hei - eventCoord.value.y;
  const right: number =
    rectPosition.value.x + rectPosition.value.wid - eventCoord.value.x;
  (userInfoRef.value?.$refs.userInfoRef as any).style.cssText += `top: ${
    top >= hei
      ? eventCoord.value.y - rectPosition.value.y
      : eventCoord.value.y - rectPosition.value.y - hei
  }px; left: ${
    right >= (wid >= 230 ? wid : 230)
      ? eventCoord.value.x - rectPosition.value.x
      : eventCoord.value.x - rectPosition.value.x - wid
  }px`;
};

/**
 * 当前查看用户资料信息时该用户的userId值
 */
const userInfoId = ref<string>("");
// 打开资料卡片逻辑
const openInfoInvoke = (userId: string, e: MouseEvent) => {
  userInfoId.value = userId;
  if (!showInfo.value) showInfo.value = true;
  nextTick(() => {
    eventCoord.value.x = e.clientX;
    eventCoord.value.y = e.clientY;
    const rect = document.getElementById("dynamicDatas")?.getBoundingClientRect()!;
    rectPosition.value.hei = rect.height;
    rectPosition.value.wid = rect.width;
    rectPosition.value.y = rect.y;
    rectPosition.value.x = rect.x;
    updatePosition();
  });
};
// 成功修改好友信息的回调
const modifyInfoSuccess = (payload: {
  userId: string;
  type: 0 | 1;
  remark?: string;
  disabledSelfLook?: boolean;
}) => {
  if (props.otherId !== props.selfId) {
    if (payload.type === 0)
      for (const value of props.data.values()) {
        if (value.userId === payload.userId) value.remark = payload.remark!;
        const thumbsData = value.thumbs.get(payload.userId);
        if (thumbsData) thumbsData.remark = payload.remark!;
        const commentData = value.comments;
        for (const { commenter, commenteder } of commentData.values()) {
          if (commenter.userId === payload.userId) commenter.remark = payload.remark!;
          if (commenteder?.userId === payload.userId)
            commenteder.remark = payload.remark!;
        }
      }
    else if (payload.disabledSelfLook && props.otherId === payload.userId)
      props.data.clear();
  }
};

// 点击头像，打开资料卡片
const openInfo = (userId: string, avatar: string, e: MouseEvent) => {
  if (props.isFriend || props.isSelf) openInfoInvoke(userId, e);
  else imgClick([avatar], 0);
};

/**
 * 给动态数据的根元素一个ref属性
 */
const dynamicDatasRef = ref<any>();
/**
 * 滚动的最大高度
 */
const scrollMax = ref<number>(0);
/**
 * 是否正在加载更多动态数据
 */
const isLoadingMore = ref<boolean>(false);
/**
 * 滚动条是否滚动到底部
 */
const scrollBottom = ref<boolean>(false);
/**
 * 该动态数据的最后一条动态的id值
 */
const lastId = ref<string>("");

// 获取最后一条动态的id值
const getLastId = () => {
  const arrDatas = [...props.data];
  lastId.value = arrDatas[arrDatas.length - 1][0];
};

watch(
  () => props.data.size,
  (newSize: number) => {
    getLastId();
    if (newSize < 3 && !props.isLast) {
      isLoadingMore.value = true;
      scrollBottom.value = true;
      nextTick(() => {
        scrollRef.value.update();
        requestDatas(lastId.value);
      });
    }
  },
  { immediate: true }
);

/**
 * 加载是否出错
 */
const isLoadingMoreError = ref<boolean>(false);
const getScrollMax = () =>
  (scrollMax.value =
    dynamicDatasRef.value.scrollHeight - dynamicDatasRef.value.offsetHeight);
// 开始请求历史动态数据
const requestDatas = (lastDynamicId: string) => {
  if (isLoadingMoreError.value) isLoadingMoreError.value = false;
  dynamicStore
    .getDynamic({
      senderId: props.selfId,
      userId: props.otherId,
      lastDynamicId,
      isSelfDynamic: props.isSelf ? props.isSelf : undefined,
    })
    .then((res) => {
      if (res.code === 1) {
        scrollBottom.value = false;
        emits("update:isLast", res.isLast);
        if (props.otherId !== props.selfId)
          for (const [key, value] of res.dynamicDatas) props.data.set(key, value);
        getLastId();
        nextTick(() => {
          getScrollMax();
          isLoadingMore.value = false;
        });
      } else isLoadingMoreError.value = true;
    })
    .catch(() => {
      isLoadingMore.value = false;
      isLoadingMoreError.value = true;
      scrollRef.value.update();
    });
};

// 给评论操作菜单一个ref属性
const commentMenuRef = ref<any>();
const openCommentMenu = (payload: {
  commentid: string;
  dynamicid: string;
  e: MouseEvent;
  isDelete: boolean;
  commenteder: Commenter;
  showreplay: boolean;
}) => {
  (commentMenuRef.value as any).openMenu(payload);
};

// 当滚动条开始滚动时
const scroll = ({ scrollTop }: { scrollTop: number }) => {
  if (showInfo.value) showInfo.value = false;
  if (showMenu.value) showMenu.value = false;
  if (commentMenuRef.value.showMenu) commentMenuRef.value.showMenu = false;
  if (
    !isLoadingMoreError.value &&
    !isLoadingMore.value &&
    !scrollBottom.value &&
    !props.isLast &&
    scrollTop + 5 >= scrollMax.value
  ) {
    isLoadingMore.value = true;
    scrollBottom.value = true;
    nextTick(() => {
      scrollRef.value.update();
      requestDatas(lastId.value);
    });
  }
};

/**
 * 是否开始挂载资料卡片组件
 */
const isMounted = ref<boolean>(false);
onMounted(() => {
  isMounted.value = true;
  setTimeout(() => {
    if (dynamicDatasRef.value) getScrollMax();
  });
});

defineExpose({
  showInfo,
  showMenu,
});
</script>

<style lang="scss" scoped>
.dynamicDatas {
  max-height: 290px;
  font-size: 14px;

  %layout {
    display: grid;
    grid-row-gap: 5px;
    grid-column-gap: 5px;
  }

  .sender {
    &-left {
      @include setWidHei(45px, 45px);
      object-fit: cover;
      border-radius: 50%;
      float: left;
      cursor: pointer;
    }

    &-right {
      float: left;
      margin-left: 15px;
    }

    &-remark {
      @include setWidHei(365px, 22px);
      box-sizing: border-box;
      position: relative;

      & > span {
        color: $dynamicRemark;
      }

      .dynamic-opea {
        font-size: 22px;
        float: right;
        cursor: pointer;
      }
    }

    &-text {
      margin: 3px 0 8px 0;
      max-width: 280px;
      word-break: break-all;
      white-space: pre-wrap;
    }

    &-imgs {
      margin-top: 8px;

      img {
        object-fit: cover;
        cursor: pointer;
      }

      &__one {
        img {
          @include setWidHei(280px, 170px);
        }
      }

      &__two {
        @extend %layout;
        grid-template-columns: 180px 180px;

        img {
          @include setWidHei(180px, 140px);
        }
      }

      &__three {
        @extend %layout;
        grid-template-columns: 120px 120px 120px;

        img {
          @include setWidHei(120px, 110px);
        }
      }
    }

    &-time {
      margin: 8px 0 0;
      color: $dimFontCor;
      font-size: 13px;
    }

    &-divider {
      width: 370px;
      float: left;
      margin-left: 60px;

      &__last {
        margin-top: 0;
        border-top: 0;
      }
    }
  }

  .loading-more {
    text-align: center;
    padding: 10px 0;
    margin-top: -10px;

    .spinMess {
      font-size: 19px;
    }

    &__error {
      transition: color 0.2s;
      font-size: 13px;

      span:hover {
        cursor: pointer;
        color: rgb(250, 12, 12);
        text-decoration: underline;
      }
    }
  }
}
</style>
